/*
 * UString.cpp
 *
 *  Created on: 2020年3月24日
 *      Author: chuanjiang.zh
 */

#include "UString.h"
#include <utility>
#include <algorithm>
#include <stdexcept>
#include <iostream>
#include <stdio.h>
#include <stdarg.h>
#include <cstring>
#include <string.h>


class UStringPrivate : public std::string
{
public:

};


static bool contains(const char* pattern, size_t length, char ch)
{
    for (size_t i = 0; i < length; ++ i)
    {
        if (pattern[i] == ch)
        {
            return true;
        }
    }
    return false;
}


UString::UString():
    m_pimpl(new UStringPrivate())
{
}

UString::~UString()
{
    delete m_pimpl;
}

UString::UString(const char* str):
    m_pimpl(new UStringPrivate())
{
    m_pimpl->assign(str);
}

UString::UString(const UString& str):
		m_pimpl(new UStringPrivate())
{
	*m_pimpl = *str.m_pimpl;
}

UString::UString(const char* str, size_t length):
		m_pimpl(new UStringPrivate())
{
	m_pimpl->assign(str, length);
}


UString::UString(size_t length):
		m_pimpl(new UStringPrivate())
{
	m_pimpl->resize(length);
}

UString::UString(size_t num, const char& ch):
		m_pimpl(new UStringPrivate())
{
	m_pimpl->assign(num, ch);
}


UString& UString::operator = (const char* str)
{
	m_pimpl->assign(str);
	return *this;
}

UString& UString::operator = (const UString& str)
{
	*m_pimpl = *str.m_pimpl;
	return *this;
}

UString& UString::operator = (char ch)
{
	str() = ch;
	return *this;
}

UString& UString::assign(size_t num, const char& ch)
{
	m_pimpl->assign(num, ch);
	return *this;
}

UString& UString::assign(const UString& other)
{
	*m_pimpl = *other.m_pimpl;
	return *this;
}

UString& UString::assign(const char* str)
{
	m_pimpl->assign(str);
	return *this;
}

UString& UString::assign(const char* str, size_t length)
{
	m_pimpl->assign(str, length);
	return *this;
}


void UString::swap(UString& other)
{
	m_pimpl->swap(*other.m_pimpl);
}


size_t UString::size() const
{
	return m_pimpl->size();
}

size_t UString::length() const
{
	return m_pimpl->length();
}

size_t UString::capacity() const
{
	return m_pimpl->capacity();
}

size_t UString::max_size() const
{
	return m_pimpl->max_size();
}

bool UString::empty() const
{
	return m_pimpl->empty();
}

char& UString::at(size_t idx)
{
	return m_pimpl->at(idx);
}

const char& UString::at(size_t idx) const
{
	return m_pimpl->at(idx);
}

const char* UString::c_str() const
{
	return m_pimpl->c_str();
}

const char* UString::data() const
{
	return m_pimpl->data();
}

char* UString::data()
{
	return const_cast<char*>(m_pimpl->data());
}


char& UString::operator[](size_t idx)
{
	return str()[idx];
}

const char& UString::operator[] (size_t idx) const
{
	return str()[idx];
}

bool UString::operator == (const UString& other) const
{
	return str() == other.str();
}

bool UString::operator != (const UString& other) const
{
	return str() != other.str();
}

bool UString::operator < (const UString& other) const
{
	return str() < other.str();
}

bool UString::operator <= (const UString& other) const
{
	return str() <= other.str();
}

bool UString::operator > (const UString& other) const
{
	return str() > other.str();
}


bool UString::operator >= (const UString& other) const
{
	return str() >= other.str();
}


bool UString::operator == (const char* s) const
{
	return str() == s;
}

bool UString::operator != (const char* s) const
{
	return str() != s;
}

bool UString::operator < (const char* s) const
{
	return str() < s;
}

bool UString::operator <= (const char* s) const
{
	return str() <= s;
}

bool UString::operator > (const char* s) const
{
	return str() > s;
}

bool UString::operator >= (const char* s) const
{
	return str() >= s;
}

int UString::compare(const char* str) const
{
	return m_pimpl->compare(str);
}

int UString::compare(const UString& other) const
{
	return m_pimpl->compare(*other.m_pimpl);
}

UString UString::operator + (char ch)
{
	m_pimpl->append(1, ch);
    return *this;
}

UString UString::operator + (const char* str)
{
	m_pimpl->append(str, strlen(str));
    return *this;
}

UString UString::operator + (const UString& other)
{
	m_pimpl->append(other.c_str(), other.size());
    return *this;
}

UString& UString::operator += (char ch)
{
	m_pimpl->append(1, ch);
    return *this;
}

UString& UString::operator += (const char* str)
{
	m_pimpl->append(str);
    return *this;
}

UString& UString::operator += (const UString& other)
{
	m_pimpl->append(*other.m_pimpl);
    return *this;
}


UString& UString::append(size_t num, char ch)
{
	m_pimpl->append(num, ch);
	return *this;
}

UString& UString::append(const char* str)
{
	m_pimpl->append(str);
	return *this;
}

UString& UString::append(const char* str, size_t length)
{
	m_pimpl->append(str, length);
	return *this;
}

UString& UString::append(const UString& other)
{
	m_pimpl->append(*other.m_pimpl);
	return *this;
}


UString& UString::insert(size_t idx, size_t num, char ch)
{
	m_pimpl->insert(idx, num, ch);
	return *this;
}

UString& UString::insert(size_t idx, const char* str)
{
	m_pimpl->insert(idx, str);
	return *this;
}

UString& UString::insert(size_t idx, const char* str, size_t length)
{
	m_pimpl->insert(idx, str, length);
	return *this;
}

UString& UString::insert(size_t idx, const UString& other)
{
	m_pimpl->insert(idx, *other.m_pimpl);
	return *this;
}

UString& UString::replace(size_t idx, size_t num, const char* str)
{
	m_pimpl->replace(idx, num, str);
	return *this;
}

UString& UString::replace(size_t idx, size_t num, const char* str, size_t length)
{
	m_pimpl->replace(idx, num, str, length);
	return *this;
}

UString& UString::replace(size_t idx, size_t num, const UString& other)
{
	m_pimpl->replace(idx, num, other.str());
	return *this;
}

void UString::reserve(size_t length)
{
	m_pimpl->reserve(length);
}

void UString::resize(size_t length, char ch)
{
	m_pimpl->resize(length, ch);
}

UString& UString::erase(size_t idx, size_t num)
{
	m_pimpl->erase(idx, num);
	return *this;
}

void UString::clear()
{
	m_pimpl->clear();
}

size_t UString::copy(char* buffer, size_t length, size_t fromIdx) const
{
	return m_pimpl->copy(buffer, length, fromIdx);
}

size_t UString::find(const UString& other, size_t idx) const
{
	return m_pimpl->find(other.str(), idx);
}

size_t UString::find(const char* str, size_t idx) const
{
	return m_pimpl->find(str, idx);
}

size_t UString::find(const char* str, size_t idx, size_t length) const
{
	return m_pimpl->find(str, idx, length);
}

size_t UString::find(char ch, size_t idx) const
{
	return m_pimpl->find(ch, idx);
}

size_t UString::rfind(const UString& other, size_t idx) const
{
	return m_pimpl->rfind(other.str(), idx);
}

size_t UString::rfind(const char* str, size_t idx) const
{
	return m_pimpl->rfind(str, idx);
}

size_t UString::rfind(const char* str, size_t idx, size_t length) const
{
	return m_pimpl->rfind(str, idx, length);
}

size_t UString::rfind(char ch, size_t idx) const
{
	return m_pimpl->rfind(ch, idx);
}

UString UString::substr(size_t idx, size_t num) const
{
	std::string str = m_pimpl->substr(idx, num);
	return UString(str.c_str(), str.size());
}


//size_t UString::format(const char* fmt, ...);


int UString::icompare(const char* str) const
{
#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
    return _stricmp(c_str(), str);
#else
    return strcasecmp(c_str(), str);
#endif
}

int UString::icompare(const UString& other) const
{
	return icompare(other.c_str());
}

UString& UString::toLower()
{
	std::string& str = this->str();
    for (size_t idx = 0; idx < size(); ++idx)
    {
    	str[idx] = tolower(str[idx]);
    }

	return *this;
}

UString& UString::toUpper()
{
	std::string& str = this->str();
    for (size_t idx = 0; idx < size(); ++idx)
    {
    	str[idx] = toupper(str[idx]);
    }

	return *this;
}

size_t UString::remove(char ch)
{
	std::string& str = this->str();
    size_t len = size();
    str.erase(std::remove(str.begin(), str.end(), ch), str.end());
    return (len - str.size());
}

bool UString::contains(char ch) const
{
    size_t pos = find(ch);
    return (pos != std::string::npos);
}

bool UString::contains(const char* str) const
{
    size_t pos = find(str);
    return (pos != std::string::npos);
}

bool UString::contains(const char* str, size_t length) const
{
    size_t pos = find(str, length);
    return (pos != std::string::npos);
}

bool UString::contains(const UString& other) const
{
    size_t pos = find(other.c_str(), other.size());
    return (pos != std::string::npos);
}

bool UString::startWith(char ch) const
{
	if (empty())
	{
		return false;
	}
	return str()[0] == ch;
}

bool UString::startWith(const char* pattern) const
{
	return startWith(pattern, strlen(pattern));
}

bool UString::startWith(const char* pattern, size_t length) const
{
	if (size() < length)
	{
		return false;
	}

	for (size_t i = 0; i < length; ++ i)
	{
		if ((*this)[i] != pattern[i])
		{
			return false;
		}
	}
	return true;
}

bool UString::startWith(const UString& pattern) const
{
	return startWith(pattern.c_str(), pattern.size());
}

bool UString::endWith(char ch) const
{
	if (empty())
	{
		return false;
	}
	return str()[size() - 1] == ch;
}

bool UString::endWith(const char* pattern) const
{
	return endWith(pattern, strlen(pattern));
}

bool UString::endWith(const char* pattern, size_t length) const
{
	if (size() < length)
	{
		return false;
	}

	size_t fromIdx = size() - length;
	for (size_t i = 0; i < length; ++ i)
	{
		if ((*this)[fromIdx + i] != pattern[i])
		{
			return false;
		}
	}
	return true;
}

bool UString::endWith(const UString& pattern) const
{
	return endWith(pattern.c_str(), pattern.size());
}

UString& UString::trimLeft()
{
	return trimLeft(" \r\n\t");
}

UString& UString::trimLeft(char ch)
{
	if (size() > 0)
	{
	    size_t count = 0;
	    for (size_t i = 0; i < size(); ++ i)
	    {
	        if (at(i) == ch)
	        {
	            count ++;
	        }
	        else
	        {
	            break;
	        }
	    }

	    if (count > 0)
	    {
	        erase(0, count);
	    }
	}
	return *this;
}

UString& UString::trimLeft(const char* pattern)
{
	return trimLeft(pattern, strlen(pattern));
}

UString& UString::trimLeft(const char* pattern, size_t length)
{
    if (size() > 0)
    {
		size_t count = 0;
		for (size_t i = 0; i < size(); ++ i)
		{
			if (::contains(pattern, length, str()[i]))
			{
				count ++;
			}
			else
			{
				break;
			}
		}

		if (count > 0)
		{
			erase(0, count);
		}
    }
	return *this;
}

UString& UString::trimRight()
{
	return trimRight(" \r\n\t");
}

UString& UString::trimRight(char ch)
{
	if (size() > 0)
	{
	    size_t pos = std::string::npos;
	    for (size_t i = size() - 1; i != std::string::npos; i --)
	    {
	        if (str()[i] == ch)
	        {
	            pos = i;
	        }
	        else
	        {
	            break;
	        }
	    }

	    if (pos != std::string::npos)
	    {
	        erase(pos);
	    }
    }
	return *this;
}

UString& UString::trimRight(const char* pattern)
{
	return trimRight(pattern, strlen(pattern));
}

UString& UString::trimRight(const char* pattern, size_t length)
{
    if (size() > 0)
    {
		size_t pos = std::string::npos;
		for (size_t i = size() - 1; i != std::string::npos; i --)
		{
			if (::contains(pattern, length, str()[i]))
			{
				pos = i;
			}
			else
			{
				break;
			}
		}

		if (pos != std::string::npos)
		{
			erase(pos);
		}
    }
	return *this;
}

UString& UString::trim()
{
	trimLeft();
	trimRight();
	return *this;
}

UString& UString::trim(const char* pattern)
{
	trimLeft(pattern);
	trimRight(pattern);
	return *this;
}


std::string& UString::str()
{
	return *m_pimpl;
}

const std::string& UString::str() const
{
	return *m_pimpl;
}

void UString::create()
{
	m_pimpl = new UStringPrivate();
}
